/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package utn.tsb.tej.comunications.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import utn.tsb.tej.comunications.Commands;
import utn.tsb.tej.comunications.GameData;
import utn.tsb.tej.world_logic.Player;

/**
 * This class has all the necesari behavior to interact with a new players
 * that wants the data of the room game.
 * Gives to the player the data of the game, and recibe the personal data of
 * the player. This class has nothing to do with players who wants to join
 * the game.
 * @author Carlos S. Moreno <CarlosS.Moreno@gmail.com>
 */
public class NewPlayerRequest implements Runnable {

    private Socket playerSocket;
    private InputStream iStream;
    private ObjectInputStream objectInput;
    private OutputStream oStream;
    private ObjectOutputStream objectOutput;

    /**
     * Parameter constructor. Ask for a Socket with the connection with the
     * player that request the data of the game.
     * @param playerSocket
     */
    public NewPlayerRequest(Socket playerSocket) {
        this.playerSocket = playerSocket;
    }

    @Override
    public void run() {
        //for (int i = 0; i < 3; i++) {//try to connect with the player N times
        try {
            String address = playerSocket.getInetAddress().getHostAddress();
            prepareInputStream();
            prepareOutputStream();
            switch (objectInput.readInt()) {
                case Commands.GAMEDATA:
                    /*
                     * The player wants just the the Game Data.
                     * Send the game data from the RoomGame unique instance
                     */
                    GameData gd = RoomGame.getInstance().getGameData();
                    objectOutput.writeObject(gd);
                    //objectData.flush();
                    break;
                case Commands.JOINGAME:
                    //The player wants to join the game
                    RoomGame rGame = RoomGame.getInstance();

                    if (!rGame.anyEmptyPlace()) {//if there are no empty places on the room
                        objectOutput.writeBoolean(false);
                        objectOutput.flush();
                        break;
                    }
                    //If there are an empty place.
                    objectOutput.writeBoolean(true);
                    objectOutput.flush();
                    Player newPlayer = new Player();
                    //Recive the new players nickname
                    newPlayer.setNickName(objectInput.readUTF());
                    //Assing a color
                    newPlayer.setColor(rGame.getAnAvailableColor());
                    //Sending the color
                    objectOutput.writeObject(newPlayer.getColor());
                    //objectData.flush();
                    //Saves the player address
                    newPlayer.setAddress(playerSocket.getInetAddress().getHostAddress());
                    rGame.addPlayer(newPlayer);
                    objectOutput.writeObject(rGame);
                    objectOutput.flush();
                    break;
                case Commands.GET_ROOMGAME_UPDATE:
                    /*
                     * A player that is already in the room is asking
                     * the server for the last version of the Room Game
                     * Data.
                     */
                    //First, it check if the player is really in the Room
                    if (!RoomGame.getInstance().vaidateAddress(address)) {
                        objectOutput.writeInt(Commands.CANCEL);
                        break;
                    }

                    objectOutput.writeInt(Commands.ACCEPT);
                    objectOutput.writeObject(RoomGame.getInstance());
                    objectOutput.flush();
                    break;
                case Commands.PLAYER_UPDATE:

                    /*
                     * A player want to send an update of its data:
                     * Nickname, color, ready.
                     */
                    Player playerToUpdate = (Player) objectInput.readObject();
                    RoomGame rg = RoomGame.getInstance();

                    if (rg.vaidateAddress(address)) {
                        //Sends an OK to continue
                        objectOutput.writeBoolean(true);
                        Player player = rg.getPlayerByAddress(address);
                        player.setNickName(playerToUpdate.getNickName());
                        player.setReady(playerToUpdate.isReady());

                        //Check if the color is change
                        if (player.getColor().compareTo(playerToUpdate.getColor()) != 0) {

                            //If change, it checks if the new color is available
                            if (rg.isColorAvailable(playerToUpdate.getColor())) {//If it is, then it update to the new color and sends an OK
                                //Add the old player's color to the list of availables colors
                                rg.addColor(player.getColor());
                                //Then removes from the list the new Players Color
                                rg.removeColor(playerToUpdate.getColor());
                                //And set the new player's color
                                player.setColor(playerToUpdate.getColor());

                                objectOutput.writeBoolean(true);
                            } else //If it is not, then it keep the old one. And sends a FAIL color change
                            {
                                objectOutput.writeBoolean(false);
                                objectOutput.writeObject(player.getColor());
                            }
                        } else//If didn't change, sends an OK.
                        {
                            objectOutput.writeBoolean(true);
                        }
                    } else {
                         //No player with the address registered, send a false to continue.
                        objectOutput.writeBoolean(false);
                    }

                    objectOutput.flush();

                    //System.out.println(RoomGame.getInstance().getPlayerByAddress(address).toString());

                    break;
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(NewPlayerRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(NewPlayerRequest.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (playerSocket.isConnected()) {
                    closeConnection();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        //}//End For
    }

    private void prepareInputStream() throws IOException {
        //Prepare the Input streams
        iStream = playerSocket.getInputStream(); //Gets de conection intput stream
        objectInput = new ObjectInputStream(iStream); //Creates the Data stream
    }

    private void prepareOutputStream() throws IOException {
        //Prepeare the Output streams
        oStream = playerSocket.getOutputStream(); //Gets the connection output stream
        objectOutput = new ObjectOutputStream(oStream); //Creates the Objects stream
        objectOutput.flush();
    }

    private void closeConnection() throws IOException {
        objectOutput.close();
        objectInput.close();
        playerSocket.close();
    }
}
